package com.example.Nurse_Notifier;

import android.app.Activity;
import android.util.Log;
import interfaces.ChangeState;
import interfaces.HandleReceivedData;
import interfaces.NotifyUser;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;

public class PackageAnalyzer implements HandleReceivedData {

    private ArrayList<ChangeState> changeStatesList;
    private ArrayList<NotifyUser> notifyUser;
    private XbeeDeviceContainer xbeeDeviceContainer;
    private Activity activity;
    private static final int EVENT_ADD_DEVICE = 0;
    private static final int EVENT_REMOVE_DEVICE = 1;
    private static final int EVENT_CHANGE_DEVICE_STATE = 2;
    private boolean lockChange = false;
    byte[] data;
    int length;

    public PackageAnalyzer(ArrayList<ChangeState> changeStates, XbeeDeviceContainer xbeeDeviceContainer,
                           Activity activity, ArrayList<NotifyUser> notifyUser) {
        this.changeStatesList = changeStates;
        this.xbeeDeviceContainer = xbeeDeviceContainer;
        this.activity = activity;
        this.notifyUser = notifyUser;
    }

    @Override
    public void getData(final byte[] data, final int length) {
        this.data = data;
        this.length = length;
        activity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                getContentStatus(data, length);
            }
        });
    }

    public void getContentStatus(byte[] data, int length) {
        switch (UdpServer.getLineInPack(data)) {
            case UdpServer.LINE_BLOCKS_COUNT: {
                int devsCount = data[length - 3] << 8 | data[length - 4];
                if (devsCount < xbeeDeviceContainer.size()) {
                    Log.i("An awkward situation", "Devices count somehow decreased");

                } else if (devsCount > xbeeDeviceContainer.size()) {
                    int devCnt = xbeeDeviceContainer.size();
                    int cnt = data[length - 4] - devCnt;
                    for (int i = 0; i < cnt; i++) {
                        transmitToListeners(new XbeeDevice(activity, "", (devCnt + i),
                                UdpServer.DEVICE_OFF), i, EVENT_ADD_DEVICE, -1);
                    }
                }
                break;
            }
            case UdpServer.LINE_ADDRSS: {
                Log.i("SK", "Content status: LINE ADDRESS");

                byte[] mac = new byte[4];
                mac[0] = data[11];
                mac[1] = data[12];
                mac[2] = data[13];
                mac[3] = data[14];
                xbeeDeviceContainer.get(UdpServer.getBlockInPack(data)).setMac(mac);
                Log.i("SK", "Mac setted in device number" + UdpServer.getBlockInPack(data) + " mac -> "
                        + Arrays.toString(mac));
//                }
                break;
            }

            case UdpServer.LINE_STATUS: {

                Log.i("SK", "Content status: LINE STATUS (Line status)");
                int id = UdpServer.getBlockInPack(data);
                if (id + 1 > xbeeDeviceContainer.size() || (id == 0 && xbeeDeviceContainer.size() == 0)) {
                    transmitToListeners(new XbeeDevice(activity, "", id,
                            data[length - 3]), id, EVENT_ADD_DEVICE, -1);
                }
                for (int i = 0; i < xbeeDeviceContainer.size(); i++) {
                    if (!lockChange) {
                        if (xbeeDeviceContainer.get(i).getStatus() != data[length - 3] &&
                                xbeeDeviceContainer.get(i).getId() ==
                                        UdpServer.getBlockInPack(data)) {
                            transmitToListeners(null, i, EVENT_CHANGE_DEVICE_STATE, data[length - 3]);
                        }
                    } else {
                        lockChange = false;
                    }
                    if (xbeeDeviceContainer.get(i).getId() == UdpServer.getBlockInPack(data) && data[length - 3] ==
                            UdpServer.DEVICE_ALARM) {
                        Log.i("SK", "Notifying about alarm!!!!");
                        for (NotifyUser nu : notifyUser) {
                            nu.notifyAlarm(UdpServer.getBlockInPack(data));
                        }
                    }

//                    if (xbeeDeviceContainer.get(i).getId() == UdpServer.getBlockInPack(data) && data[length - 3] ==
//                            UdpServer.DEVICE_OFF) {
//                        Log.i("SK", "Notifying about removing device");
//                        transmitToListeners(null, -1, EVENT_REMOVE_DEVICE, -1);
//                    }

                }
                break;
            }

            case UdpServer.LINE_STATUS_CH_REQ: {
                lockChange = true;
                Log.i("SK", "Updating device status (Status change request)");
                for (int i = 0; i < xbeeDeviceContainer.size(); i++) {
                    if (xbeeDeviceContainer.get(i).getStatus() != data[length - 3] &&
                            xbeeDeviceContainer.get(i).getId() ==
                                    UdpServer.getBlockInPack(data)) {
                        transmitToListeners(null, i, EVENT_CHANGE_DEVICE_STATE, data[length - 3]);
                    }
                }
                break;
            }

            case UdpServer.LINE_ADC: {
                Log.i("SK", "Content status: LINE ADC");
                break;
            }

            case UdpServer.LINE_ADC_FIXED: {
                Log.i("SK", "Content status: LINE ADC FIXED");
                break;
            }

            case UdpServer.LINE_PING_COUNT: {
                Log.i("SK", "Content status: LINE PING COUNT");
                break;
            }

            case UdpServer.LINE_BUTTON_STATUS: {
                Log.i("SK", "Content status: LINE BUTTON STATUS");
                if (xbeeDeviceContainer.size() > 0) {
                    for (NotifyUser nu : notifyUser) {
                        nu.notifyButtonPressed(UdpServer.getBlockInPack(data), data[length - 3] != 0);
                    }
                }
                break;
            }
        }
    }

    public void addTransmitListener(ChangeState transmitListener) {
        changeStatesList.add(transmitListener);
    }

    public void removeTransmitListener(int indx) {
        changeStatesList.remove(indx);
    }

    public void removeAll() {
        changeStatesList.clear();
    }

    public void addAll(Collection<ChangeState> collection) {
        changeStatesList.addAll(collection);
    }

    public void transmitToListeners(XbeeDevice xbeeDevice, int objectId, int event, int status) {
        switch (event) {
            case EVENT_ADD_DEVICE: {
                for (ChangeState cs : changeStatesList) {
                    cs.addObject(xbeeDevice);
                }
                break;
            }

            case EVENT_REMOVE_DEVICE: {
                for (int i = 0; i < changeStatesList.size(); i++) {
                    changeStatesList.get(i).removeObject(i);
                }
                break;
            }

            case EVENT_CHANGE_DEVICE_STATE: {
                for (ChangeState cs : changeStatesList) {
                    cs.changeObjectStatus(objectId, status);
                }
                break;
            }
        }
    }
}